package com.upb.webserver.user;

import cn.hutool.core.collection.CollectionUtil;
import com.upb.webserver.application.ApplicationManager;
import com.upb.webserver.chain.ChainManager;
import com.upb.webserver.chain.ChainService;
import com.upb.webserver.common.enums.PlatformEnum;
import com.upb.webserver.common.exception.WebServerException;
import com.upb.webserver.common.pojo.base.BasePageResponse;
import com.upb.webserver.common.returncode.ConstantCode;
import com.upb.webserver.common.tools.JsonUtils;
import com.upb.webserver.company.CompanyDeveloperService;
import com.upb.webserver.dao.entity.TbApplication;
import com.upb.webserver.dao.mapper.TbChainMapper;
import com.upb.webserver.dao.mapper.TbOrgMapper;
import com.upb.webserver.dao.mapper.TbUserMapper;
import com.upb.webserver.org.OrgManager;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.SetUtils;
import org.apache.commons.collections4.map.HashedMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

@Slf4j
@Service
public class UserService {
    @Autowired
    private TbUserMapper userMapper;
    @Autowired
    private OrgManager orgManager;
    @Autowired
    private TbOrgMapper orgMapper;

    @Autowired
    private ApplicationManager applicationManager;
    @Autowired
    private CompanyDeveloperService companyDeveloperService;
    @Autowired
    private ChainService chainService;
    @Autowired
    private ChainManager chainManager;
    @Autowired
    private TbChainMapper chainMapper;
    @Autowired
    private UserServiceFactory userServiceFactory;


    /**
     * @param platform
     * @param currentAccountId
     * @param pageNumber
     * @param pageSize
     * @param chainId
     * @param chainType
     * @param applicationId
     * @return
     */
    public BasePageResponse queryByPage(Byte platform, int currentAccountId, int pageNumber, int pageSize, Integer chainId, byte chainType, Integer applicationId) {

        Map<String, Object>  restParam = new HashedMap<>();
        if (PlatformEnum.DEVELOPER.getId() == platform) {
            restParam = initParamForDeveloper(currentAccountId, chainId, chainType, applicationId);
        } else {
            TbApplication applicationById = applicationManager.verifyApplicationId(applicationId);
            restParam.put("chainIds", Arrays.asList(chainId));
            restParam.put("appIds", Arrays.asList(applicationById.getFinalName()));
        }

        if (Objects.isNull(restParam)) {
            log.info("finish exec method[queryUserByPage] ,restParam result is null");
            return BasePageResponse.initialize();
        }

        restParam.put("pageNumber", pageNumber <= 0 ? 1 : pageNumber);
        restParam.put("pageSize", pageSize <= 0 ? 20 : pageSize);

        log.info("restParam:{}", JsonUtils.objToString(restParam));
        return userServiceFactory.getUserServiceByChainType(chainType).queryUserPage(restParam);
    }


    /**
     * @param currentAccountId
     * @param chainId
     * @param chainType
     * @param applicationId
     * @return
     */
    private Map<String, Object> initParamForDeveloper(int currentAccountId, Integer chainId, Byte chainType, Integer applicationId) {
        log.info("start exec method [initParamForDeveloper]. currentAccountId:{} chainId:{} chainType:{} applicationId:{}", currentAccountId, chainId, chainType, applicationId);
        int companyId = companyDeveloperService.selectCompanyIdByDeveloperId(currentAccountId);
        Set<String> applicationFinalNameSet = applicationManager.getFinalNameByCompanyId(companyId);
        Set<Integer> chainIdSet = chainManager.getChainIdSetByCompanyIdList(Arrays.asList(companyId));

        if (CollectionUtil.isEmpty(chainIdSet) && CollectionUtil.isEmpty(applicationFinalNameSet)) {
            log.info("not found application or chain by company:{}", companyId);
            return null;
        }

        //param:chainId
        if (chainId != null) {
            if (CollectionUtil.isNotEmpty(chainIdSet) && !chainIdSet.contains(chainId)) {
                log.warn("fail exec method [initParamForDeveloper]. inputChainId:{} but support:{}", chainId, JsonUtils.objToString(chainIdSet));
                throw new WebServerException(ConstantCode.INVALID_CHAIN_ID);
            }
            chainIdSet = SetUtils.hashSet(chainId);
        }

        //param:applicationId
        if (Objects.nonNull(applicationId)) {
            TbApplication applicationById = applicationManager.verifyApplicationId(applicationId);
            if (CollectionUtil.isNotEmpty(applicationFinalNameSet) && !applicationFinalNameSet.contains(applicationById.getFinalName())) {
                log.warn("fail exec method [initParamForDeveloper]. inputApplicationId:{} but support:{}", applicationId, JsonUtils.objToString(applicationFinalNameSet));
                throw new WebServerException(ConstantCode.APPLICATION_ID_INVALID);
            }
            applicationFinalNameSet = SetUtils.hashSet(applicationById.getFinalName());
        }


        //rest param
        Map<String, Object> restParam = new HashedMap<>();
        restParam.put("chainIds", chainIdSet);
        restParam.put("appIds", applicationFinalNameSet);

        log.info("success exec method[initParamForDeveloper]. result:{}", JsonUtils.objToString(restParam));
        return restParam;
    }


}
